﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Spacer {
	public enum MouseButton : int {
		None = 0,
		Left = 1,
		Right = 2,
		Middle = 3,
		XButton1 = 4,
		XButton2 = 5
	}
	
	public enum GamePadButton : int {
		None = 0,
		BigButton = 1,
		Start = 2,
		Back = 3,
		Up = 4,
		Down = 5,
		Left = 6,
		Right = 7,
		A = 8,
		B = 9,
		X = 10,
		Y = 11,
		LeftStick = 12,
		RightStick = 13,
		LeftBumper = 14,
		RightBumper = 15
	}

	public enum BindingType : int {
		Keyboard = 256, // Start after Keys for Dictionary IEqualityComparer
		Mouse = 512,
		GamePad = 1024
	}

	public struct Binding {
		BindingType m_eType;
		Keys m_eKey;
		MouseButton m_eMouseButton;
		GamePadButton m_eGamePadButton;
		string m_strCommand;

		// ----------

		public BindingType Type {
			get { return m_eType; }
			set {
				m_eType = BindingType.Keyboard;
				m_eKey = Keys.None;
				m_eMouseButton = MouseButton.None;
				m_eGamePadButton = GamePadButton.None;
			}
		}

		public Keys Key {
			get { return m_eKey; }
			set {
				m_eType = BindingType.Keyboard;
				m_eKey = value;
			}
		}

		public MouseButton MouseButton {
			get { return m_eMouseButton; }
			set {
				m_eType = BindingType.Mouse;
				m_eMouseButton = value;
			}
		}

		public GamePadButton GamePadButton {
			get { return m_eGamePadButton; }
			set {
				m_eType = BindingType.GamePad;
				m_eGamePadButton = value;
			}
		}

		public string Command {
			get { return m_strCommand; }
			set { m_strCommand = value; }
		}

		// ----------

		public Binding( Keys eKey, string strCommand ) {
			m_eType = BindingType.Keyboard;
			m_eKey = eKey;

			m_eMouseButton = MouseButton.None;
			m_eGamePadButton = GamePadButton.None;

			m_strCommand = strCommand;
		}

		public Binding( MouseButton eMouseButton, string strCommand ) {
			m_eType = BindingType.Mouse;
			m_eMouseButton = eMouseButton;

			m_eKey = Keys.None;
			m_eGamePadButton = GamePadButton.None;

			m_strCommand = strCommand;
		}

		public Binding( GamePadButton eGamePadButton, string strCommand ) {
			m_eType = BindingType.GamePad;
			m_eGamePadButton = eGamePadButton;

			m_eKey = Keys.None;
			m_eMouseButton = MouseButton.None;

			m_strCommand = strCommand;
		}

		public Binding( int iKeyHash, string strCommand ) {
			m_eType = BindingType.Keyboard;
			m_eGamePadButton = GamePadButton.None;
			m_eKey = Keys.None;
			m_eMouseButton = MouseButton.None;

			m_strCommand = strCommand;
			SetKeyFromHash( iKeyHash );
		}

		// ----------

		public void SetKeyFromHash( int iHash ) {
			m_eType = (BindingType)(iHash & 0xFFFF0000);
			if( m_eType == BindingType.Keyboard )
				m_eKey = (Keys)(iHash & 0x0000FFFF);
			else if( m_eType == BindingType.Mouse )
				m_eMouseButton = (MouseButton)(iHash & 0x0000FFFF);
			else if( m_eType == BindingType.GamePad )
				m_eGamePadButton = (GamePadButton)(iHash & 0x0000FFFF);
		}

		public int GetHashFromKey() {
			if( m_eType == BindingType.Keyboard )
				return ((int)m_eType | (int)m_eKey).GetHashCode();
			else if( m_eType == BindingType.Mouse )
				return ((int)m_eType | (int)m_eMouseButton).GetHashCode();
			else if( m_eType == BindingType.GamePad )
				return ((int)m_eType | (int)m_eGamePadButton).GetHashCode();
			return 0;
		}

		public override int GetHashCode() {
			return GetHashFromKey() ^ m_strCommand.GetHashCode();
		}

		public override bool Equals( object obj ) {
			return this.GetHashCode() == obj.GetHashCode();
		}
	}

	// ----------------------------------------------------------------------------------------------------

	[Flags]
	public enum CommandKeys : byte {
		None = 0,
		Up = 1,
		Down = 2,
		Left = 4,
		Right = 8,
		Jump = 16,
		Attack = 32,
		Attack2 = 64
	}

	// ----------------------------------------------------------------------------------------------------

	public struct UserCommand {
		Vector2 m_vLeftThumb, m_vRightThumb;
		float m_fLeftTrigger, m_fRightTrigger;
		CommandKeys m_flKeys;

		// ----------

		public Vector2 LeftThumb {
			get { return m_vLeftThumb; }
			set { m_vLeftThumb = value; }
		}

		public Vector2 RightThumb {
			get { return m_vRightThumb; }
			set { m_vRightThumb = value; }
		}

		public float LeftTrigger {
			get { return m_fLeftTrigger; }
			set { m_fLeftTrigger = value; }
		}

		public float RightTrigger {
			get { return m_fRightTrigger; }
			set { m_fRightTrigger = value; }
		}

		public CommandKeys Keys {
			get { return m_flKeys; }
			set { m_flKeys = value; }
		}

		// ----------

		public bool IsKeyDown( CommandKeys flKey ) {
			return (m_flKeys & flKey) > 0;
		}

		public void SetKeyDown( CommandKeys flKey ) {
			m_flKeys |= flKey;
		}

		public void UnsetKeyDown( CommandKeys flKey ) {
			m_flKeys = m_flKeys & ~flKey;
		}
	}

	// ----------------------------------------------------------------------------------------------------

	public static partial class Input {
		// State objects
		static KeyboardState[] s_KbStateOld = new KeyboardState[4], s_KbStateNew = new KeyboardState[4];
		static MouseState s_MsStateOld = new MouseState(), s_MsStateNew = new MouseState();
		static GamePadState[] s_GpStateOld = new GamePadState[4], s_GpStateNew = new GamePadState[4];

		// Cached pressed keys
		static Keys[][] s_KbKeysPressedOld = new Keys[4][], s_KbKeysPressedNew = new Keys[4][];

		// Bindings/Commands
		static Dictionary<int,Binding> s_dictBindings = new Dictionary<int,Binding>(); // Key = /*Binding.GetHashFromKey()*/
		
		public delegate void BindingEventHandler( PlayerIndex ePlayer, string strCmd, string[] arrArgs );

		static Dictionary<string,BindingEventHandler> s_dictCommands = new Dictionary<string,BindingEventHandler>();
		public static Dictionary<string,BindingEventHandler> Commands {
			get { return s_dictCommands; }
		}

		// User input
		static UserCommand[] s_arrUserCommands = new UserCommand[4];

		// ----------

		public static void Initialize() {
			DefaultCommands();
			DefaultBindings();
		}

		public static void Update( GameTime gt ) {
			#if !DEBUG
			if( !Globals.GameInstance.IsActive )
				return;
			#endif

			// Swap old mouse state and get new
			s_MsStateOld = s_MsStateNew;
			s_MsStateNew = Mouse.GetState();
			
			// Keyboard and gamepads for all 4 players
			for(int i=0;i<4;i++) {
				// Keyboards
				s_KbStateOld[i] = s_KbStateNew[i];
				s_KbStateNew[i] = Keyboard.GetState( (PlayerIndex)i );

				s_KbKeysPressedOld[i] = s_KbKeysPressedNew[i];
				s_KbKeysPressedNew[i] = s_KbStateNew[i].GetPressedKeys();

				// Gamepads
				s_GpStateOld[i] = s_GpStateNew[i];
				s_GpStateNew[i] = GamePad.GetState( (PlayerIndex)i, GamePadDeadZone.None );

				// Update gamepad information in ucmds
				s_arrUserCommands[i].LeftThumb = s_GpStateNew[i].ThumbSticks.Left;
				s_arrUserCommands[i].RightThumb = s_GpStateNew[i].ThumbSticks.Right;
				s_arrUserCommands[i].LeftTrigger = s_GpStateNew[i].Triggers.Left;
				s_arrUserCommands[i].RightTrigger = s_GpStateNew[i].Triggers.Right;
			}

			DoEvents( gt );
		}

		private static void DoEvents( GameTime gt ) {
			for(int i=0;i<4;i++) {
				if( s_KbKeysPressedNew[i] == null || s_KbKeysPressedOld[i] == null || s_GpStateNew[i] == null || s_GpStateOld[i] == null )
					continue;

				// Keyboard Events
				// Press
				foreach(Keys c in s_KbKeysPressedNew[i]) {
					bool found = false;
					foreach(Keys p in s_KbKeysPressedOld[i]) {
						if( c == p ) {
							found = true;
						}
					}

					if( !found ) {
						// Press
						OnKeyboardEvent( c, true, (PlayerIndex)i );
					}
				}

				// Release
				foreach(Keys p in s_KbKeysPressedOld[i]) {
					bool found = false;
					foreach(Keys c in s_KbKeysPressedNew[i]) {
						if( c == p ) {
							found = true;
						}
					}

					if( !found ) {
						// Release
						OnKeyboardEvent( p, false, (PlayerIndex)i );
					}
				}

				// GamePad Events
				if( s_GpStateNew[i].Buttons.BigButton == ButtonState.Pressed && s_GpStateOld[i].Buttons.BigButton == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.BigButton, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].Buttons.BigButton == ButtonState.Pressed && s_GpStateNew[i].Buttons.BigButton == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.BigButton, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].Buttons.Start == ButtonState.Pressed && s_GpStateOld[i].Buttons.Start == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Start, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].Buttons.Start == ButtonState.Pressed && s_GpStateNew[i].Buttons.Start == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Start, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].Buttons.Back == ButtonState.Pressed && s_GpStateOld[i].Buttons.Back == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Back, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].Buttons.Back == ButtonState.Pressed && s_GpStateNew[i].Buttons.Back == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Back, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].DPad.Up == ButtonState.Pressed && s_GpStateOld[i].DPad.Up == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Up, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].DPad.Up == ButtonState.Pressed && s_GpStateNew[i].DPad.Up == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Up, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].DPad.Down == ButtonState.Pressed && s_GpStateOld[i].DPad.Down == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Down, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].DPad.Down == ButtonState.Pressed && s_GpStateNew[i].DPad.Down == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Down, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].DPad.Left == ButtonState.Pressed && s_GpStateOld[i].DPad.Left == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Left, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].DPad.Left == ButtonState.Pressed && s_GpStateNew[i].DPad.Left == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Left, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].DPad.Right == ButtonState.Pressed && s_GpStateOld[i].DPad.Right == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Right, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].DPad.Right == ButtonState.Pressed && s_GpStateNew[i].DPad.Right == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Right, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].Buttons.A == ButtonState.Pressed && s_GpStateOld[i].Buttons.A == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.A, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].Buttons.A == ButtonState.Pressed && s_GpStateNew[i].Buttons.A == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.A, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].Buttons.B == ButtonState.Pressed && s_GpStateOld[i].Buttons.B == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.B, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].Buttons.B == ButtonState.Pressed && s_GpStateNew[i].Buttons.B == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.B, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].Buttons.X == ButtonState.Pressed && s_GpStateOld[i].Buttons.X == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.X, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].Buttons.X == ButtonState.Pressed && s_GpStateNew[i].Buttons.X == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.X, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].Buttons.Y == ButtonState.Pressed && s_GpStateOld[i].Buttons.Y == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Y, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].Buttons.Y == ButtonState.Pressed && s_GpStateNew[i].Buttons.Y == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.Y, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].Buttons.LeftStick == ButtonState.Pressed && s_GpStateOld[i].Buttons.LeftStick == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.LeftStick, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].Buttons.LeftStick == ButtonState.Pressed && s_GpStateNew[i].Buttons.LeftStick == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.LeftStick, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].Buttons.RightStick == ButtonState.Pressed && s_GpStateOld[i].Buttons.RightStick == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.RightStick, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].Buttons.RightStick == ButtonState.Pressed && s_GpStateNew[i].Buttons.RightStick == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.RightStick, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].Buttons.LeftShoulder == ButtonState.Pressed && s_GpStateOld[i].Buttons.LeftShoulder == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.LeftBumper, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].Buttons.LeftShoulder == ButtonState.Pressed && s_GpStateNew[i].Buttons.LeftShoulder == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.LeftBumper, false, (PlayerIndex)i );
				}
				if( s_GpStateNew[i].Buttons.RightShoulder == ButtonState.Pressed && s_GpStateOld[i].Buttons.RightShoulder == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.RightBumper, true, (PlayerIndex)i );
				} else if( s_GpStateOld[i].Buttons.RightShoulder == ButtonState.Pressed && s_GpStateNew[i].Buttons.RightShoulder == ButtonState.Released ) {
					OnGamePadEvent( GamePadButton.RightBumper, false, (PlayerIndex)i );
				}
			}

			// Mouse Events
			if( s_MsStateNew.LeftButton == ButtonState.Pressed && s_MsStateOld.LeftButton == ButtonState.Released ) {
				OnMouseEvent( MouseButton.Left, true );
			} else if( s_MsStateOld.LeftButton == ButtonState.Pressed && s_MsStateNew.LeftButton == ButtonState.Released ) {
				OnMouseEvent( MouseButton.Left, false );
			}
			if( s_MsStateNew.RightButton == ButtonState.Pressed && s_MsStateOld.RightButton == ButtonState.Released ) {
				OnMouseEvent( MouseButton.Right, true );
			} else if( s_MsStateOld.RightButton == ButtonState.Pressed && s_MsStateNew.RightButton == ButtonState.Released ) {
				OnMouseEvent( MouseButton.Right, false );
			}
			if( s_MsStateNew.MiddleButton == ButtonState.Pressed && s_MsStateOld.MiddleButton == ButtonState.Released ) {
				OnMouseEvent( MouseButton.Middle, true );
			} else if( s_MsStateOld.MiddleButton == ButtonState.Pressed && s_MsStateNew.MiddleButton == ButtonState.Released ) {
				OnMouseEvent( MouseButton.Middle, false );
			}
			if( s_MsStateNew.XButton1 == ButtonState.Pressed && s_MsStateOld.XButton1 == ButtonState.Released ) {
				OnMouseEvent( MouseButton.XButton1, true );
			} else if( s_MsStateOld.XButton1 == ButtonState.Pressed && s_MsStateNew.XButton1 == ButtonState.Released ) {
				OnMouseEvent( MouseButton.XButton1, false );
			}
			if( s_MsStateNew.XButton2 == ButtonState.Pressed && s_MsStateOld.XButton2 == ButtonState.Released ) {
				OnMouseEvent( MouseButton.XButton2, true );
			} else if( s_MsStateOld.XButton2 == ButtonState.Pressed && s_MsStateNew.XButton2 == ButtonState.Released ) {
				OnMouseEvent( MouseButton.XButton2, false );
			}
		}

		// ----------

		public static bool IsKeyDown( Keys eKey ) { return IsKeyDown( eKey, PlayerIndex.One ); }
		public static bool IsKeyDown( Keys eKey, PlayerIndex ePlayer ) {
			return s_KbStateNew[(int)ePlayer].IsKeyDown( eKey );
		}
		
		public static bool WasKeyDown( Keys eKey ) { return WasKeyDown( eKey, PlayerIndex.One ); }
		public static bool WasKeyDown( Keys eKey, PlayerIndex ePlayer ) {
			return s_KbStateOld[(int)ePlayer].IsKeyDown( eKey );
		}
		
		public static bool WasKeyPressed( Keys eKey ) { return WasKeyPressed( eKey, PlayerIndex.One ); }
		public static bool WasKeyPressed( Keys eKey, PlayerIndex ePlayer ) {
			return s_KbStateNew[(int)ePlayer].IsKeyDown( eKey ) && !s_KbStateOld[(int)ePlayer].IsKeyDown( eKey );
		}
		
		public static bool WasKeyReleased( Keys eKey ) { return WasKeyReleased( eKey, PlayerIndex.One ); }
		public static bool WasKeyReleased( Keys eKey, PlayerIndex ePlayer ) {
			return !s_KbStateNew[(int)ePlayer].IsKeyDown( eKey ) && s_KbStateOld[(int)ePlayer].IsKeyDown( eKey );
		}
		
		public static bool IsButtonDown( MouseButton eButton ) {
			switch( eButton ) {
				case MouseButton.Left:
					return s_MsStateNew.LeftButton == ButtonState.Pressed;
				case MouseButton.Middle:
					return s_MsStateNew.MiddleButton == ButtonState.Pressed;
				case MouseButton.Right:
					return s_MsStateNew.RightButton == ButtonState.Pressed;
				case MouseButton.XButton1:
					return s_MsStateNew.XButton1 == ButtonState.Pressed;
				case MouseButton.XButton2:
					return s_MsStateNew.XButton2 == ButtonState.Pressed;
			}
			return false;
		}

		public static bool WasButtonDown( MouseButton eButton ) {
			switch( eButton ) {
				case MouseButton.Left:
				return s_MsStateOld.LeftButton == ButtonState.Pressed;
				case MouseButton.Middle:
					return s_MsStateOld.MiddleButton == ButtonState.Pressed;
				case MouseButton.Right:
					return s_MsStateOld.RightButton == ButtonState.Pressed;
				case MouseButton.XButton1:
					return s_MsStateOld.XButton1 == ButtonState.Pressed;
				case MouseButton.XButton2:
					return s_MsStateOld.XButton2 == ButtonState.Pressed;
			}
			return false;
		}

		public static bool WasButtonPressed( MouseButton eButton ) {
			switch( eButton ) {
				case MouseButton.Left:
					return s_MsStateNew.LeftButton == ButtonState.Pressed && s_MsStateOld.LeftButton == ButtonState.Released;
				case MouseButton.Middle:
					return s_MsStateNew.MiddleButton == ButtonState.Pressed && s_MsStateOld.MiddleButton == ButtonState.Released;
				case MouseButton.Right:
					return s_MsStateNew.RightButton == ButtonState.Pressed && s_MsStateOld.RightButton == ButtonState.Released;
				case MouseButton.XButton1:
					return s_MsStateNew.XButton1 == ButtonState.Pressed && s_MsStateOld.XButton1 == ButtonState.Released;
				case MouseButton.XButton2:
					return s_MsStateNew.XButton2 == ButtonState.Pressed && s_MsStateOld.XButton2 == ButtonState.Released;
			}
			return false;
		}

		public static bool WasButtonReleased( MouseButton eButton ) {
			switch( eButton ) {
				case MouseButton.Left:
					return s_MsStateNew.LeftButton == ButtonState.Released && s_MsStateOld.LeftButton == ButtonState.Pressed;
				case MouseButton.Middle:
					return s_MsStateNew.MiddleButton == ButtonState.Released && s_MsStateOld.MiddleButton == ButtonState.Pressed;
				case MouseButton.Right:
					return s_MsStateNew.RightButton == ButtonState.Released && s_MsStateOld.RightButton == ButtonState.Pressed;
				case MouseButton.XButton1:
					return s_MsStateNew.XButton1 == ButtonState.Released && s_MsStateOld.XButton1 == ButtonState.Pressed;
				case MouseButton.XButton2:
					return s_MsStateNew.XButton2 == ButtonState.Released && s_MsStateOld.XButton2 == ButtonState.Pressed;
			}
			return false;
		}

		public static bool IsGamePadButtonDown( GamePadButton eButton ) { return IsGamePadButtonDown( eButton, PlayerIndex.One ); }
		public static bool IsGamePadButtonDown( GamePadButton eButton, PlayerIndex ePlayer ) {
			switch( eButton ) {
				case GamePadButton.BigButton:
					return s_GpStateNew[(int)ePlayer].Buttons.BigButton == ButtonState.Pressed;
				case GamePadButton.Start:
					return s_GpStateNew[(int)ePlayer].Buttons.Start == ButtonState.Pressed;
				case GamePadButton.Back:
					return s_GpStateNew[(int)ePlayer].Buttons.Back == ButtonState.Pressed;
				case GamePadButton.Up:
					return s_GpStateNew[(int)ePlayer].DPad.Up == ButtonState.Pressed;
				case GamePadButton.Down:
					return s_GpStateNew[(int)ePlayer].DPad.Down == ButtonState.Pressed;
				case GamePadButton.Left:
					return s_GpStateNew[(int)ePlayer].DPad.Left == ButtonState.Pressed;
				case GamePadButton.Right:
					return s_GpStateNew[(int)ePlayer].DPad.Right == ButtonState.Pressed;
				case GamePadButton.A:
					return s_GpStateNew[(int)ePlayer].Buttons.A == ButtonState.Pressed;
				case GamePadButton.B:
					return s_GpStateNew[(int)ePlayer].Buttons.B == ButtonState.Pressed;
				case GamePadButton.X:
					return s_GpStateNew[(int)ePlayer].Buttons.X == ButtonState.Pressed;
				case GamePadButton.Y:
					return s_GpStateNew[(int)ePlayer].Buttons.Y == ButtonState.Pressed;
				case GamePadButton.LeftStick:
					return s_GpStateNew[(int)ePlayer].Buttons.LeftStick == ButtonState.Pressed;
				case GamePadButton.RightStick:
					return s_GpStateNew[(int)ePlayer].Buttons.RightStick == ButtonState.Pressed;
				case GamePadButton.LeftBumper:
					return s_GpStateNew[(int)ePlayer].Buttons.LeftShoulder == ButtonState.Pressed;
				case GamePadButton.RightBumper:
					return s_GpStateNew[(int)ePlayer].Buttons.RightShoulder == ButtonState.Pressed;
			}
			return false;
		}

		public static bool WasGamePadButtonDown( GamePadButton eButton ) { return WasGamePadButtonDown( eButton, PlayerIndex.One ); }
		public static bool WasGamePadButtonDown( GamePadButton eButton, PlayerIndex ePlayer ) {
			switch( eButton ) {
				case GamePadButton.BigButton:
					return s_GpStateOld[(int)ePlayer].Buttons.BigButton == ButtonState.Pressed;
				case GamePadButton.Start:
					return s_GpStateOld[(int)ePlayer].Buttons.Start == ButtonState.Pressed;
				case GamePadButton.Back:
					return s_GpStateOld[(int)ePlayer].Buttons.Back == ButtonState.Pressed;
				case GamePadButton.Up:
					return s_GpStateOld[(int)ePlayer].DPad.Up == ButtonState.Pressed;
				case GamePadButton.Down:
					return s_GpStateOld[(int)ePlayer].DPad.Down == ButtonState.Pressed;
				case GamePadButton.Left:
					return s_GpStateOld[(int)ePlayer].DPad.Left == ButtonState.Pressed;
				case GamePadButton.Right:
					return s_GpStateOld[(int)ePlayer].DPad.Right == ButtonState.Pressed;
				case GamePadButton.A:
					return s_GpStateOld[(int)ePlayer].Buttons.A == ButtonState.Pressed;
				case GamePadButton.B:
					return s_GpStateOld[(int)ePlayer].Buttons.B == ButtonState.Pressed;
				case GamePadButton.X:
					return s_GpStateOld[(int)ePlayer].Buttons.X == ButtonState.Pressed;
				case GamePadButton.Y:
					return s_GpStateOld[(int)ePlayer].Buttons.Y == ButtonState.Pressed;
				case GamePadButton.LeftStick:
					return s_GpStateOld[(int)ePlayer].Buttons.LeftStick == ButtonState.Pressed;
				case GamePadButton.RightStick:
					return s_GpStateOld[(int)ePlayer].Buttons.RightStick == ButtonState.Pressed;
				case GamePadButton.LeftBumper:
					return s_GpStateOld[(int)ePlayer].Buttons.LeftShoulder == ButtonState.Pressed;
				case GamePadButton.RightBumper:
					return s_GpStateOld[(int)ePlayer].Buttons.RightShoulder == ButtonState.Pressed;
			}
			return false;
		}

		public static bool WasGamePadButtonPressed( GamePadButton eButton ) { return WasGamePadButtonPressed( eButton, PlayerIndex.One ); }
		public static bool WasGamePadButtonPressed( GamePadButton eButton, PlayerIndex ePlayer ) {
			switch( eButton ) {
				case GamePadButton.BigButton:
					return s_GpStateNew[(int)ePlayer].Buttons.BigButton == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].Buttons.BigButton == ButtonState.Released;
				case GamePadButton.Start:
					return s_GpStateNew[(int)ePlayer].Buttons.Start == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].Buttons.Start == ButtonState.Released;
				case GamePadButton.Back:
					return s_GpStateNew[(int)ePlayer].Buttons.Back == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].Buttons.Back == ButtonState.Released;
				case GamePadButton.Up:
					return s_GpStateNew[(int)ePlayer].DPad.Up == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].DPad.Up == ButtonState.Released;
				case GamePadButton.Down:
					return s_GpStateNew[(int)ePlayer].DPad.Down == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].DPad.Down == ButtonState.Released;
				case GamePadButton.Left:
					return s_GpStateNew[(int)ePlayer].DPad.Left == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].DPad.Left == ButtonState.Released;
				case GamePadButton.Right:
					return s_GpStateNew[(int)ePlayer].DPad.Right == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].DPad.Right == ButtonState.Released;
				case GamePadButton.A:
					return s_GpStateNew[(int)ePlayer].Buttons.A == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].Buttons.A == ButtonState.Released;
				case GamePadButton.B:
					return s_GpStateNew[(int)ePlayer].Buttons.B == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].Buttons.B == ButtonState.Released;
				case GamePadButton.X:
					return s_GpStateNew[(int)ePlayer].Buttons.X == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].Buttons.X == ButtonState.Released;
				case GamePadButton.Y:
					return s_GpStateNew[(int)ePlayer].Buttons.Y == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].Buttons.Y == ButtonState.Released;
				case GamePadButton.LeftStick:
					return s_GpStateNew[(int)ePlayer].Buttons.LeftStick == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].Buttons.LeftStick == ButtonState.Released;
				case GamePadButton.RightStick:
					return s_GpStateNew[(int)ePlayer].Buttons.RightStick == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].Buttons.RightStick == ButtonState.Released;
				case GamePadButton.LeftBumper:
					return s_GpStateNew[(int)ePlayer].Buttons.LeftShoulder == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].Buttons.LeftShoulder == ButtonState.Released;
				case GamePadButton.RightBumper:
					return s_GpStateNew[(int)ePlayer].Buttons.RightShoulder == ButtonState.Pressed && s_GpStateOld[(int)ePlayer].Buttons.RightShoulder == ButtonState.Released;
			}
			return false;
		}

		public static bool WasGamePadButtonReleased( GamePadButton eButton ) { return WasGamePadButtonReleased( eButton, PlayerIndex.One ); }
		public static bool WasGamePadButtonReleased( GamePadButton eButton, PlayerIndex ePlayer ) {
			switch( eButton ) {
				case GamePadButton.BigButton:
					return s_GpStateNew[(int)ePlayer].Buttons.BigButton == ButtonState.Released && s_GpStateOld[(int)ePlayer].Buttons.BigButton == ButtonState.Pressed;
				case GamePadButton.Start:
					return s_GpStateNew[(int)ePlayer].Buttons.Start == ButtonState.Released && s_GpStateOld[(int)ePlayer].Buttons.Start == ButtonState.Pressed;
				case GamePadButton.Back:
					return s_GpStateNew[(int)ePlayer].Buttons.Back == ButtonState.Released && s_GpStateOld[(int)ePlayer].Buttons.Back == ButtonState.Pressed;
				case GamePadButton.Up:
					return s_GpStateNew[(int)ePlayer].DPad.Up == ButtonState.Released && s_GpStateOld[(int)ePlayer].DPad.Up == ButtonState.Pressed;
				case GamePadButton.Down:
					return s_GpStateNew[(int)ePlayer].DPad.Down == ButtonState.Released && s_GpStateOld[(int)ePlayer].DPad.Down == ButtonState.Pressed;
				case GamePadButton.Left:
					return s_GpStateNew[(int)ePlayer].DPad.Left == ButtonState.Released && s_GpStateOld[(int)ePlayer].DPad.Left == ButtonState.Pressed;
				case GamePadButton.Right:
					return s_GpStateNew[(int)ePlayer].DPad.Right == ButtonState.Released && s_GpStateOld[(int)ePlayer].DPad.Right == ButtonState.Pressed;
				case GamePadButton.A:
					return s_GpStateNew[(int)ePlayer].Buttons.A == ButtonState.Released && s_GpStateOld[(int)ePlayer].Buttons.A == ButtonState.Pressed;
				case GamePadButton.B:
					return s_GpStateNew[(int)ePlayer].Buttons.B == ButtonState.Released && s_GpStateOld[(int)ePlayer].Buttons.B == ButtonState.Pressed;
				case GamePadButton.X:
					return s_GpStateNew[(int)ePlayer].Buttons.X == ButtonState.Released && s_GpStateOld[(int)ePlayer].Buttons.X == ButtonState.Pressed;
				case GamePadButton.Y:
					return s_GpStateNew[(int)ePlayer].Buttons.Y == ButtonState.Released && s_GpStateOld[(int)ePlayer].Buttons.Y == ButtonState.Pressed;
				case GamePadButton.LeftStick:
					return s_GpStateNew[(int)ePlayer].Buttons.LeftStick == ButtonState.Released && s_GpStateOld[(int)ePlayer].Buttons.LeftStick == ButtonState.Pressed;
				case GamePadButton.RightStick:
					return s_GpStateNew[(int)ePlayer].Buttons.RightStick == ButtonState.Released && s_GpStateOld[(int)ePlayer].Buttons.RightStick == ButtonState.Pressed;
				case GamePadButton.LeftBumper:
					return s_GpStateNew[(int)ePlayer].Buttons.LeftShoulder == ButtonState.Released && s_GpStateOld[(int)ePlayer].Buttons.LeftShoulder == ButtonState.Pressed;
				case GamePadButton.RightBumper:
					return s_GpStateNew[(int)ePlayer].Buttons.RightShoulder == ButtonState.Released && s_GpStateOld[(int)ePlayer].Buttons.RightShoulder == ButtonState.Pressed;
			}
			return false;
		}

		public static Vector2 MousePos() { return MousePos( false ); }
		public static Vector2 MousePos( bool bNoCache ) {
			return (!bNoCache ? new Vector2(s_MsStateNew.X,s_MsStateNew.Y) : new Vector2(Mouse.GetState().X,Mouse.GetState().Y));
		}

		public static Vector2 MousePosLast() {
			return new Vector2( s_MsStateOld.X,  s_MsStateOld.Y );
		}

		// ----------

		public static UserCommand GetUserCmd( PlayerIndex ePlayer ) {
			return s_arrUserCommands[(int)ePlayer];
		}

		// ----------

		#region Input::Default*()
		private static void DefaultCommands() {
			s_dictCommands.Clear();

			//s_dictCommands.Add( "joingame", new BindingEventHandler(CONCMD_JoinGame) );
			//s_dictCommands.Add( "exitgame", new BindingEventHandler(CONCMD_ExitGame) );

			s_dictCommands.Add( "nextitem", new BindingEventHandler(CONCMD_NextItem) );
			s_dictCommands.Add( "previtem", new BindingEventHandler(CONCMD_PrevItem) );
			s_dictCommands.Add( "in_reset", new BindingEventHandler(ResetDefaultBindings) );

			s_dictCommands.Add( "+up", new BindingEventHandler(UCMD_Up_Press) );
			s_dictCommands.Add( "-up", new BindingEventHandler(UCMD_Up_Release) );

			s_dictCommands.Add( "+down", new BindingEventHandler(UCMD_Down_Press) );
			s_dictCommands.Add( "-down", new BindingEventHandler(UCMD_Down_Release) );

			s_dictCommands.Add( "+left", new BindingEventHandler(UCMD_Left_Press) );
			s_dictCommands.Add( "-left", new BindingEventHandler(UCMD_Left_Release) );

			s_dictCommands.Add( "+right", new BindingEventHandler(UCMD_Right_Press) );
			s_dictCommands.Add( "-right", new BindingEventHandler(UCMD_Right_Release) );

			s_dictCommands.Add( "+jump", new BindingEventHandler(UCMD_Jump_Press) );
			s_dictCommands.Add( "-jump", new BindingEventHandler(UCMD_Jump_Release) );

			s_dictCommands.Add( "+attack", new BindingEventHandler(UCMD_Attack_Press) );
			s_dictCommands.Add( "-attack", new BindingEventHandler(UCMD_Attack_Release) );

			s_dictCommands.Add( "+attack2", new BindingEventHandler(UCMD_Attack2_Press) );
			s_dictCommands.Add( "-attack2", new BindingEventHandler(UCMD_Attack2_Release) );
		}

		private static void ResetDefaultBindings( PlayerIndex ePlayer, string strCmd, string[] arrArgs ) { DefaultBindings(true); }
		private static void DefaultBindings() { DefaultBindings(false); }
		private static void DefaultBindings( bool bReset ) {
			s_dictBindings.Clear();

			foreach(KeyValuePair<int,string> kv in Configuration.Bindings) {
				s_dictBindings.Add( kv.Key, new Binding(kv.Key,kv.Value) );
			}
			
			if( s_dictBindings.Count == 0 ) {
				Binding temp;

				// Keyboard
				/*temp = new Binding( Keys.Enter, "joingame" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( Keys.Escape, "exitgame" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );
			
				temp = new Binding( Keys.W, "+up" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( Keys.S, "+down" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( Keys.A, "+left" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( Keys.D, "+right" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( Keys.Space, "+jump" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( Keys.Q, "previtem" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( Keys.E, "nextitem" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );*/

				// Mouse
				/*temp = new Binding( MouseButton.Left, "+attack" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( MouseButton.Right, "+attack2" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );*/

				// Gamepad
				temp = new Binding( GamePadButton.Start, "joingame" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( GamePadButton.Back, "exitgame" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( GamePadButton.Up, "+up" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( GamePadButton.Down, "+down" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( GamePadButton.Left, "+left" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( GamePadButton.Right, "+right" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( GamePadButton.A, "+jump" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( GamePadButton.B, "+attack" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( GamePadButton.Y, "+attack2" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( GamePadButton.LeftBumper, "previtem" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );

				temp = new Binding( GamePadButton.RightBumper, "nextitem" );
				s_dictBindings.Add( temp.GetHashFromKey(), temp );
			}
		}
		#endregion

		#region Input::On*Event()
		private static void OnKeyboardEvent( Keys eKey, bool bPress, PlayerIndex ePlayer ) {
			//Console.WriteLine( "Keyboard: " + eKey.ToString() + " " + (bPress ? "Pressed" : "Released") + " by player " + ePlayer.ToString() );

			Binding buffer;
			if( s_dictBindings.TryGetValue((int)BindingType.Keyboard|(int)eKey,out buffer) ) {
				// TODO: Split commands correctly (Parse strings)
				string[] commands = buffer.Command.Split( new char[]{';'}, StringSplitOptions.RemoveEmptyEntries );
				foreach(string command in commands) {
					int space = command.IndexOf( ' ' );

					string cmd = (space == -1 ? command : command.Substring(0,space));
					string[] args = (space == -1 ? new string[]{} : command.Substring(space+1).Split(' '));

					/*if( cmd[0] == '+' && !bPress ) {
						cmd = '-' + cmd.Substring( 1 );
					}*/
					if( !bPress ) {
						if( cmd[0] == '+' )
							cmd = '-' + cmd.Substring( 1 );
						else
							continue;
					}

					BindingEventHandler func;
					if( s_dictCommands.TryGetValue(cmd,out func) ) {
						func( ePlayer, cmd, args );
					}
				}
			}
		}

		private static void OnMouseEvent( MouseButton eButton, bool bPress ) {
			//Console.WriteLine( "Mouse: " + eButton.ToString() + " " + (bPress ? "Pressed" : "Released") );

			Binding buffer;
			if( s_dictBindings.TryGetValue((int)BindingType.Mouse|(int)eButton,out buffer) ) {
				// TODO: Split commands correctly (Parse strings)
				string[] commands = buffer.Command.Split( new char[]{';'}, StringSplitOptions.RemoveEmptyEntries );
				foreach(string command in commands) {
					int space = command.IndexOf( ' ' );

					string cmd = (space == -1 ? command : command.Substring(0,space));
					string[] args = (space == -1 ? new string[]{} : command.Substring(space+1).Split(' '));

					/*if( cmd[0] == '+' && !bPress ) {
						cmd = '-' + cmd.Substring( 1 );
					}*/
					if( !bPress ) {
						if( cmd[0] == '+' )
							cmd = '-' + cmd.Substring( 1 );
						else
							continue;
					}


					BindingEventHandler func;
					if( s_dictCommands.TryGetValue(cmd,out func) ) {
						func( PlayerIndex.One, cmd, args );
					}
				}
			}
		}

		private static void OnGamePadEvent( GamePadButton eButton, bool bPress, PlayerIndex ePlayer ) {
			//Console.WriteLine( "GamePad: " + eButton.ToString() + " " + (bPress ? "Pressed" : "Released") + " by player " + ePlayer.ToString() );

			Binding buffer;
			if( s_dictBindings.TryGetValue((int)BindingType.GamePad|(int)eButton,out buffer) ) {
				// TODO: Split commands correctly (Parse strings)
				string[] commands = buffer.Command.Split( new char[]{';'}, StringSplitOptions.RemoveEmptyEntries );
				foreach(string command in commands) {
					int space = command.IndexOf( ' ' );

					string cmd = (space == -1 ? command : command.Substring(0,space));
					string[] args = (space == -1 ? new string[]{} : command.Substring(space+1).Split(' '));

					/*if( cmd[0] == '+' && !bPress ) {
						cmd = '-' + cmd.Substring( 1 );
					}*/
					if( !bPress ) {
						if( cmd[0] == '+' )
							cmd = '-' + cmd.Substring( 1 );
						else
							continue;
					}

					BindingEventHandler func;
					if( s_dictCommands.TryGetValue(cmd,out func) ) {
						func( ePlayer, cmd, args );
					}
				}
			}
		}
		#endregion

		// ----------

		public static void SaveBindings() {
			Configuration.Bindings.Clear();

			foreach(KeyValuePair<int,Binding> kv in s_dictBindings) {
				Configuration.Bindings.Add( kv.Key, kv.Value.Command );
			}

			Configuration.Save();
		}
	}
}
